package ca.scotthyndman.web.swf;

import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

/**
 * Helper functions used by the SWF compiler.
 * 
 * @author Scott Hyndman
 */
public final class CompilerUtils {

	/**
	 * Alphanumeric characters.
	 */
	private static final char[] ALPHANUMERIC_CHARS;

	/**
	 * Generates a random string of length <code>length</code> composed of
	 * alpha-numeric characters (both uppercase and lowercase).
	 * 
	 * @param length
	 *            The number of characters in the random string
	 * @return The random string
	 */
	public static String generateRandomString(int length) {
		return generateRandomString(length, ALPHANUMERIC_CHARS);
	}

	/**
	 * Generates a random string of length <code>length</code> using the
	 * characters found in <code>availableChars</code>. The string is built
	 * using Java's random class, so the string is not truly randomized.
	 * 
	 * @param length
	 *            The number of characters in the random string
	 * @param availableChars
	 *            The characters that will compose the random string
	 * @return The random string
	 */
	public static String generateRandomString(int length, char[] availableChars) {
		int range = availableChars.length;
		StringBuilder builder = new StringBuilder(); // not synchronized
		Random rand = new Random();

		for (int i = 0; i < length; i++) {
			builder.append(availableChars[rand.nextInt(range)]);
		}

		return builder.toString();
	}

	/**
	 * Slurps up the contents of an input stream.
	 * 
	 * @param in
	 *            The stream to read from
	 * @return The string contents of the stream
	 * @throws IOException
	 *             If an error is encountered during reading
	 */
	public static String readStringFromStream(InputStream in)
			throws IOException {
		StringBuffer out = new StringBuffer();
		byte[] b = new byte[4096];
		for (int n; (n = in.read(b)) != -1;) {
			out.append(new String(b, 0, n));
		}
		return out.toString();
	}

	/**
	 * Reads a byte array from an input stream.
	 * 
	 * @param input
	 *            The input stream
	 * @param length
	 *            The number of bytes
	 * @return The byte array of the streams contents
	 * @throws IOException
	 * @throws CompileException
	 */
	public static byte[] readBytesFromStream(InputStream input, long length)
			throws IOException, CompileException {
		byte[] bytes;
		//
		// Create bytes array
		//
		bytes = new byte[(int) length];

		//
		// Fill it
		//
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
				&& (numRead = input.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}

		//
		// Make sure we got everything
		//
		if (offset < bytes.length) {
			throw new CompileException(
					"An error was encountered while reading the compiled swf "
							+ "file. The entire file could not be read.");
		}
		return bytes;
	}

	/**
	 * Generates an array of characters available for the random string default
	 * overload.
	 */
	static {
		ALPHANUMERIC_CHARS = new char[62];

		int cnt = 0;

		//
		// Uppercase
		//
		for (int i = 65; i < 65 + 26; i++) {
			ALPHANUMERIC_CHARS[cnt++] = (char) i;
		}

		//
		// Lowercase
		//
		for (int i = 97; i < 97 + 26; i++) {
			ALPHANUMERIC_CHARS[cnt++] = (char) i;
		}

		//
		// Digits
		//
		for (int i = 48; i < 48 + 10; i++) {
			ALPHANUMERIC_CHARS[cnt++] = (char) i;
		}
	}

}
